/**
 * @file FileIO.cpp
 * @brief 文件输入输出处理类的实现
 * 
 * 实现了高性能的文件读写功能，包括：
 * 1. 内存映射文件读取
 * 2. 大缓冲区写入优化
 * 3. UTF-16LE编码支持
 * 4. 跨平台实现
 */

#include "FileIO.h"
#include <fstream>
#include <sstream>
#include <iomanip>
#include <stdexcept>
#include <iostream>
#include <locale>

#ifdef _WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#endif

// 在文件开头添加静态成员变量的定义
GridData FileIO::grid_data;

/**
 * @brief 内存映射文件类构造函数
 * 
 * 初始化所有成员变量为空值或无效值:
 * - Windows平台: 文件句柄和映射句柄设为nullptr
 * - POSIX平台: 文件描述符设为-1,长度设为0
 * - 映射数据指针设为nullptr
 */
FileIO::MemoryMappedFile::MemoryMappedFile() :
#ifdef _WIN32
    hFile(nullptr), hMapping(nullptr),
#else
    fd(-1), length(0),
#endif
    data(nullptr)
{
}

/**
 * @brief 内存映射文件类析构函数
 */
FileIO::MemoryMappedFile::~MemoryMappedFile()
{
#ifdef _WIN32
    if (data)
        UnmapViewOfFile(data);
    if (hMapping)
        CloseHandle(hMapping);
    if (hFile)
        CloseHandle(hFile);
#else
    if (data != MAP_FAILED && data != nullptr)
        munmap(data, length);
    if (fd != -1)
        close(fd);
#endif
}

/**
 * @brief 打开并映射文件
 */
bool FileIO::MemoryMappedFile::open(const std::string &filename, size_t &fileSize)
{
#ifdef _WIN32
    hFile = CreateFileA(filename.c_str(),
                       GENERIC_READ,
                       FILE_SHARE_READ,
                       NULL,
                       OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL,
                       NULL);

    if (hFile == INVALID_HANDLE_VALUE)
        return false;

    LARGE_INTEGER size;
    if (!GetFileSizeEx(hFile, &size))
    {
        CloseHandle(hFile);
        return false;
    }
    fileSize = size.QuadPart;

    hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if (!hMapping)
    {
        CloseHandle(hFile);
        return false;
    }

    data = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
    if (!data)
    {
        CloseHandle(hMapping);
        CloseHandle(hFile);
        return false;
    }
#else
    fd = ::open(filename.c_str(), O_RDONLY);
    if (fd == -1)
        return false;

    struct stat sb;
    if (fstat(fd, &sb) == -1)
    {
        close(fd);
        return false;
    }
    fileSize = sb.st_size;
    length = fileSize;

    data = mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fd, 0);
    if (data == MAP_FAILED)
    {
        close(fd);
        return false;
    }
#endif
    return true;
}

/**
 * @brief 获取映射的内存数据指针
 */
void *FileIO::MemoryMappedFile::getData() const
{
    return data;
}

/**
 * @brief 检查文件是否存在
 * @param filename 要检查的文件路径
 * @return 如果文件存在且可访问则返回true
 * @throw std::runtime_error 当文件不存在或无法访问时抛出异常
 */
bool FileIO::checkFileExists(const std::string &filename)
{
    std::ifstream file(filename);
    if (!file)
    {
        throw std::runtime_error("文件不存在或无法访问: " + filename);
    }
    return true;
}

/**
 * @brief 快速字符串转浮点数
 */
double FileIO::fastStringToDouble(const char* &p)
{
    while (*p == ' ' || *p == '\t') ++p;

    bool negative = false;
    if (*p == '-')
    {
        negative = true;
        ++p;
    }

    double result = 0.0;
    while (*p >= '0' && *p <= '9')
    {
        result = result * 10 + (*p - '0');
        ++p;
    }

    if (*p == '.')
    {
        ++p;
        double fraction = 0.1;
        while (*p >= '0' && *p <= '9')
        {
            result += (*p - '0') * fraction;
            fraction *= 0.1;
            ++p;
        }
    }

    while (*p == ' ' || *p == '\t') ++p;
    return negative ? -result : result;
}

/**
 * @brief 快速字符串转整数
 */
int FileIO::fastStringToInt(const char* &p)
{
    while (*p == ' ' || *p == '\t') ++p;

    bool negative = false;
    if (*p == '-')
    {
        negative = true;
        ++p;
    }

    int result = 0;
    while (*p >= '0' && *p <= '9')
    {
        result = result * 10 + (*p - '0');
        ++p;
    }

    while (*p == ' ' || *p == '\t') ++p;
    return negative ? -result : result;
}

/**
 * @brief 读取网格文件
 * @param filename 输入的角点网格文件路径
 * @param grid_data 输出参数，存储读取的网格数据
 * @throw std::runtime_error 当文件读取或解析失败时抛出异常
 */
void FileIO::readGridFile(const std::string &filename, GridData &grid_data)
{
    try {
        std::ifstream file(filename, std::ios::in | std::ios::binary);
        if (!file)
        {
            throw std::runtime_error("无法打开文件: " + filename);
        }

        // 使用大缓冲区
        const int READ_BUFFER_SIZE = 1024 * 1024 * 8;  // 8MB读取缓冲区
        std::unique_ptr<char[]> buffer(new char[READ_BUFFER_SIZE]);
        file.rdbuf()->pubsetbuf(buffer.get(), READ_BUFFER_SIZE);

        std::string line;
        std::string current_keyword;
        bool reading_data = false;

        // 预分配line的空间
        line.reserve(4096);

        // 使用更高效的字符串分割方法
        auto split = [](const std::string& s) -> std::vector<std::string> {
            std::vector<std::string> result;
            size_t start = 0;
            size_t end = 0;
            while ((end = s.find_first_of(" \t", start)) != std::string::npos) {
                if (end > start)
                    result.push_back(s.substr(start, end - start));
                start = s.find_first_not_of(" \t", end);
                if (start == std::string::npos)
                    break;
            }
            if (start < s.length())
                result.push_back(s.substr(start));
            return result;
        };

        while (std::getline(file, line))
        {
            // 跳过空行和注释行
            if (line.empty() || line[0] == '--')
                continue;

            // 去除行尾的空格和制表符
            if (line.back() == '\r' || line.back() == '\n' || line.back() == ' ' || line.back() == '\t')
                line.erase(line.find_last_not_of(" \t\r\n") + 1);
            
            // 检查是否是数据结束标记
            if (line[0] == '/')
            {
                reading_data = false;
                current_keyword.clear();
                continue;
            }

            // 检查关键字
            if (line.find("SPECGRID") != std::string::npos)
            {
                current_keyword = "SPECGRID";
                reading_data = true;
                continue;
            }
            else if (line.find("COORD") != std::string::npos)
            {
                current_keyword = "COORD";
                reading_data = true;
                size_t coord_size = (grid_data.size.Nx + 1) * (grid_data.size.Ny + 1) * 6;
                grid_data.coord_data.reserve(coord_size);
                continue;
            }
            else if (line.find("ZCORN") != std::string::npos)
            {
                current_keyword = "ZCORN";
                reading_data = true;
                size_t zcorn_size = 8 * grid_data.size.Nx * grid_data.size.Ny * grid_data.size.Nz;
                grid_data.zcorn_data.reserve(zcorn_size);
                continue;
            }
            else if (line.find("ACTNUM") != std::string::npos)
            {
                current_keyword = "ACTNUM";
                reading_data = true;
                size_t actnum_size = grid_data.size.Nx * grid_data.size.Ny * grid_data.size.Nz;
                grid_data.actnum_data.reserve(actnum_size);
                continue;
            }

            if (!reading_data || current_keyword.empty())
                continue;

            // 处理数据行
            if (current_keyword == "SPECGRID")
            {
                auto values = split(line);
                if (values.size() >= 3)
                {
                    grid_data.size.Nx = std::stoi(values[0]);
                    grid_data.size.Ny = std::stoi(values[1]);
                    grid_data.size.Nz = std::stoi(values[2]);
                }
            }
            else if (current_keyword == "COORD" || current_keyword == "ZCORN")
            {
                auto values = split(line);
                for (const auto& value : values)
                {
                    try {
                        if (value.find('*') != std::string::npos)
                        {
                            size_t pos = value.find('*');
                            int count = std::stoi(value.substr(0, pos));
                            std::string num_str = value.substr(pos + 1);
                            double num = std::stod(num_str);
                            
                            std::vector<NodeData> &target = 
                                (current_keyword == "COORD") ? grid_data.coord_data : grid_data.zcorn_data;
                            target.reserve(target.size() + count);
                            for (int i = 0; i < count; ++i)
                            {
                                target.emplace_back(num, num_str);
                            }
                        }
                        else
                        {
                            double num = std::stod(value);
                            if (current_keyword == "COORD")
                                grid_data.coord_data.emplace_back(num, value);
                            else
                                grid_data.zcorn_data.emplace_back(num, value);
                        }
                    }
                    catch (const std::exception& e) {
                        continue;
                    }
                }
            }
            else if (current_keyword == "ACTNUM")
            {
                auto values = split(line);
                for (const auto& value : values)
                {
                    try {
                        if (value.find('*') != std::string::npos)
                        {
                            size_t pos = value.find('*');
                            int count = std::stoi(value.substr(0, pos));
                            int num = std::stoi(value.substr(pos + 1));
                            grid_data.actnum_data.reserve(grid_data.actnum_data.size() + count);
                            grid_data.actnum_data.insert(grid_data.actnum_data.end(), count, num);
                        }
                        else
                        {
                            grid_data.actnum_data.push_back(std::stoi(value));
                        }
                    }
                    catch (const std::exception& e) {
                        continue;
                    }
                }
            }
        }

        // 验证数据大小
        size_t expected_coord_size = (grid_data.size.Nx + 1) * (grid_data.size.Ny + 1) * 6;
        size_t expected_zcorn_size = 8 * grid_data.size.Nx * grid_data.size.Ny * grid_data.size.Nz;
        size_t expected_actnum_size = grid_data.size.Nx * grid_data.size.Ny * grid_data.size.Nz;

        if (grid_data.coord_data.size() != expected_coord_size ||
            grid_data.zcorn_data.size() != expected_zcorn_size ||
            grid_data.actnum_data.size() != expected_actnum_size)
        {
            throw std::runtime_error("数据大小不符合预期");
        }

        FileIO::grid_data = grid_data;
    }
    catch (const std::exception &e)
    {
        throw std::runtime_error("读取文件时发生错误: " + std::string(e.what()));
    }
}

/**
 * @brief 解析网格数据行
 */
void FileIO::processGridLine(const std::string &line,
                           const std::string &keyword,
                           GridData &grid_data)
{
    std::istringstream iss(line);
    
    if (keyword == "SPECGRID")
    {
        int nx, ny, nz;
        iss >> nx >> ny >> nz;
        
        grid_data.size.Nx = nx;
        grid_data.size.Ny = ny;
        grid_data.size.Nz = nz;

        // 预分配空间
        size_t coord_size = (grid_data.size.Nx + 1) * (grid_data.size.Ny + 1) * 6;
        size_t zcorn_size = 8 * grid_data.size.Nx * grid_data.size.Ny * grid_data.size.Nz;
        size_t actnum_size = grid_data.size.Nx * grid_data.size.Ny * grid_data.size.Nz;

        grid_data.coord_data.reserve(coord_size);
        grid_data.zcorn_data.reserve(zcorn_size);
        grid_data.actnum_data.reserve(actnum_size);
    }
    else if (keyword == "COORD" || keyword == "ZCORN")
    {
        std::string value;
        while (iss >> value)
        {
            if (value.find('*') != std::string::npos)
            {
                size_t pos = value.find('*');
                int count = std::stoi(value.substr(0, pos));
                std::string num_str = value.substr(pos + 1);
                double num = std::stod(num_str);
                
                std::vector<NodeData> &target = 
                    (keyword == "COORD") ? grid_data.coord_data : grid_data.zcorn_data;
                for (int i = 0; i < count; ++i)
                {
                    target.emplace_back(num, num_str);
                }
            }
            else
            {
                double num = std::stod(value);
                if (keyword == "COORD")
                    grid_data.coord_data.emplace_back(num, value);
                else
                    grid_data.zcorn_data.emplace_back(num, value);
            }
        }
    }
    else if (keyword == "ACTNUM")
    {
        std::string value;
        while (iss >> value)
        {
            if (value.find('*') != std::string::npos)
            {
                size_t pos = value.find('*');
                int count = std::stoi(value.substr(0, pos));
                int num = std::stoi(value.substr(pos + 1));
                grid_data.actnum_data.insert(grid_data.actnum_data.end(), count, num);
            }
            else
            {
                grid_data.actnum_data.push_back(std::stoi(value));
            }
        }
    }
}

/**
 * @brief 保存VTK格式的网格文件
 * @param filename 输出VTK文件的路径
 * @param data 要保存的网格数据，包含节点坐标、单元连接关系和断层节点信息
 * @throw std::runtime_error 当文件创建或写入失败时抛出异常
 */
void FileIO::writeVTKFile(const std::string &filename, const ProcessedData &data)
{
    // 以二进制模式打开文件以提高写入性能
    std::ofstream file(filename, std::ios::out | std::ios::binary);
    if (!file)
    {
        throw std::runtime_error("无法创建输出文件: " + filename);
    }

    // 使用64MB大缓冲区优化IO性能
    const int BUFFER_SIZE = 1024 * 1024 * 64;  
    std::unique_ptr<char[]> buffer(new char[BUFFER_SIZE]);
    file.rdbuf()->pubsetbuf(buffer.get(), BUFFER_SIZE);

    // 预分配8MB字符串缓冲区避免频繁重新分配
    std::string str_buffer;
    str_buffer.reserve(1024 * 1024 * 8);  

    // 写入VTK文件头部信息
    str_buffer = "# vtk DataFile Version 2.0\nUnstructured Grid Example\nASCII\nDATASET UNSTRUCTURED_GRID\n\n";
    file.write(str_buffer.c_str(), str_buffer.size());

    // 写入节点坐标数据
    str_buffer = "POINTS " + std::to_string(data.nodes.size()) + " float\n";
    file.write(str_buffer.c_str(), str_buffer.size());

    // 使用stringstream优化数字到字符串的转换
    std::stringstream ss;
    ss.precision(11);
    
    // 批量写入节点坐标数据
    str_buffer.clear();
    for (const auto &node : data.nodes)
    {
        // 写入每个节点的x,y,z坐标
        for (int i = 1; i <= 3; ++i)
        {
            double value = node[i];
            // 对于整数值使用整数格式输出
            if (std::abs(value - std::round(value)) < 1e-10)
            {
                str_buffer += std::to_string(static_cast<int>(std::round(value)));
            }
            else
            {
                ss.str("");
                ss.clear();
                ss << value;
                str_buffer += ss.str();
            }
            str_buffer += (i < 3 ? " " : "\n");

            // 当缓冲区达到1MB时写入文件
            if (str_buffer.size() > 1024 * 1024)
            {
                file.write(str_buffer.c_str(), str_buffer.size());
                str_buffer.clear();
            }
        }
    }
    // 写入剩余数据
    if (!str_buffer.empty())
    {
        file.write(str_buffer.c_str(), str_buffer.size());
    }
    file.write("\n", 1);

    // 计算有效单元数量和总大小
    size_t valid_elements = 0;
    size_t total_size = 0;
    for (const auto &element : data.elements)
    {
        if (element.size() >= 5)  // 只统计有效单元
        {
            valid_elements++;
            total_size += element.size();
        }
    }

    // 写入单元连接信息
    str_buffer = "CELLS " + std::to_string(valid_elements) + " " + std::to_string(total_size) + "\n";
    file.write(str_buffer.c_str(), str_buffer.size());

    // 批量写入单元节点索引
    str_buffer.clear();
    for (const auto &element : data.elements)
    {
        if (element.size() >= 5)
        {
            // 写入节点数量和节点索引
            str_buffer += std::to_string(element.size() - 1);
            for (size_t i = 1; i < element.size(); ++i)
            {
                str_buffer += " " + std::to_string(element[i] - 1);
            }
            str_buffer += "\n";

            // 使用较小的写入阈值(512KB)提高写入频率
            if (str_buffer.size() > 512 * 1024)
            {
                file.write(str_buffer.c_str(), str_buffer.size());
                str_buffer.clear();
                file.flush(); // 确保数据写入磁盘
            }
        }
    }
    if (!str_buffer.empty())
    {
        file.write(str_buffer.c_str(), str_buffer.size());
        file.flush();
    }

    // 确保最后的换行符写入
    file.write("\n", 1);
    file.flush();

    // 写入单元类型
    str_buffer = "CELL_TYPES " + std::to_string(valid_elements) + "\n";
    file.write(str_buffer.c_str(), str_buffer.size());

    // 批量写入单元类型
    str_buffer.clear();
    for (const auto &element : data.elements)
    {
        if (element.size() >= 5)
        {
            // 根据节点数量确定单元类型
            if (element.size() == 5)
                str_buffer += "10\n";  // 四面体单元
            else if (element.size() == 7)
                str_buffer += "13\n";  // 六面体单元
            else if (element.size() == 9)
                str_buffer += "12\n";  // 三棱柱单元

            // 同样使用512KB的写入阈值
            if (str_buffer.size() > 512 * 1024)
            {
                file.write(str_buffer.c_str(), str_buffer.size());
                str_buffer.clear();
                file.flush();
            }
        }
    }
    if (!str_buffer.empty())
    {
        file.write(str_buffer.c_str(), str_buffer.size());
        file.flush();
    }

    // 写入断层节点标记数据
    file.write("\n", 1);  // 添加额外的换行符
    str_buffer = "POINT_DATA " + std::to_string(data.nodes.size()) + "\n";
    str_buffer += "SCALARS IsFaultNode int 1\n";
    str_buffer += "LOOKUP_TABLE default\n";
    file.write(str_buffer.c_str(), str_buffer.size());

    // 批量写入断层节点标记
    str_buffer.clear();
    for (const auto &node : data.nodes)
    {
        // 检查节点是否为断层节点
        int nodeId = static_cast<int>(node[0]);
        str_buffer += std::to_string(data.fault_nodes.count(nodeId) ? 1 : 0) + "\n";

        // 使用相同的写入阈值
        if (str_buffer.size() > 512 * 1024)
        {
            file.write(str_buffer.c_str(), str_buffer.size());
            str_buffer.clear();
            file.flush();
        }
    }
    if (!str_buffer.empty())
    {
        file.write(str_buffer.c_str(), str_buffer.size());
        file.flush();
    }

    // 关闭文件前确保所有数据都已写入
    file.close();
}

/**
 * @brief 保存断层节点信息到文件
 */
void FileIO::writeFaultNodesFile(const std::string &filename, const ProcessedData &data)
{
    std::ofstream file(filename);
    if (!file)
    {
        throw std::runtime_error("无法创建断层节点文件: " + filename);
    }

    // 使用与源数据同的格式输出
    file.unsetf(std::ios::fixed | std::ios::scientific);
    file.precision(11);  // 使用足够的精度

    for (const auto &nodeId : data.fault_nodes)
    {
        const auto &node = data.nodes[nodeId - 1];
        file << nodeId << " "
             << node[1] << " "
             << node[2] << " "
             << node[3] << "\n";
    }
}